<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd">
<html lang="zh-CN"><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><meta http-equiv="Content-Language" content="zh-CN"><link href="stylesheet.css" media="all" rel="stylesheet" type="text/css">
<title>规划器使用的统计信息</title>
<script> var _hmt = _hmt || []; (function() { var hm = document.createElement("script"); hm.src = "https://hm.baidu.com/hm.js?d286c55b63a3c54a1e43d10d4c203e75"; var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(hm, s); })(); </script>
</head><body class="SECT1">
<div>
<table summary="Header navigation table" width="100%" border="0" cellpadding="0" cellspacing="0">
<tr><th colspan="5" align="center" valign="bottom">PostgreSQL 8.2.3 中文文档</th></tr>
<tr><td width="10%" align="left" valign="top"><a href="using-explain.html" accesskey="P">后退</a></td><td width="10%" align="left" valign="top"><a href="performance-tips.html">快退</a></td><td width="60%" align="center" valign="bottom">章13. 性能提升技巧</td><td width="10%" align="right" valign="top"><a href="performance-tips.html">快进</a></td><td width="10%" align="right" valign="top"><a href="explicit-joins.html" accesskey="N">前进</a></td></tr>
</table>
<hr align="LEFT" width="100%"></div>
<div class="SECT1"><h1 class="SECT1"><a name="PLANNER-STATS">13.2. 规划器使用的统计信息</a></h1><a name="AEN16863"></a>
<p>就像我们在上一节里展示的那样，查询规划器需要估计一个查询检索的行数，这样才能选择正确的查询规划。本节就系统用于这些估计的统计进行一些描述。</p>
<p>统计的一个部分就是每个表和索引中的记录总数，以及每个表和索引占据的磁盘块数。这个信息保存在 <a href="catalog-pg-class.html"><tt class="STRUCTNAME">pg_class</tt></a> 表的 <tt class="STRUCTFIELD">reltuples</tt> 和 <tt class="STRUCTFIELD">relpages</tt> 字段中。我们可以用类似下面的查询检索这些信息：</p>
<pre class="SCREEN">SELECT relname, relkind, reltuples, relpages FROM pg_class WHERE relname LIKE 'tenk1%';

       relname        | relkind | reltuples | relpages
----------------------+---------+-----------+----------
 tenk1                | r       |     10000 |      358
 tenk1_hundred        | i       |     10000 |       30
 tenk1_thous_tenthous | i       |     10000 |       30
 tenk1_unique1        | i       |     10000 |       30
 tenk1_unique2        | i       |     10000 |       30
(5 rows)</pre>
<p>我们在这里可以看到 <tt class="STRUCTNAME">tenk1</tt> 有 10000 行，它的索引也有这么多行，但是索引远比表小得多(很正常)。</p>
<p>出于效率考虑，<tt class="STRUCTFIELD">reltuples</tt> 和 <tt class="STRUCTFIELD">relpages</tt> 不是实时更新的，因此它们通常包含可能有些过时的数值。它们被 <tt class="COMMAND">VACUUM</tt>, <tt class="COMMAND">ANALYZE</tt> 和几个DDL命令(比如 <tt class="COMMAND">CREATE INDEX</tt>)更新。一个独立的 <tt class="COMMAND">ANALYZE</tt>(没有和<tt class="COMMAND">VACUUM</tt> 在一起)生成一个 <tt class="STRUCTFIELD">reltuples</tt> 的近似数值，因为它并没有读取表里的每一行。规划器将把 <tt class="STRUCTNAME">pg_class</tt> 表里面的数值调整为和当前的物理表尺寸匹配，以此获取一个更接近的近似值。</p>
<a name="AEN16884"></a>
<p>大多数查询只是检索表中行的一部分，因为它们有限制待查行的 <tt class="LITERAL">WHERE</tt> 子句。因此规划器需要对 <tt class="LITERAL">WHERE</tt> 子句的<i class="FIRSTTERM">选择性</i>进行评估，选择性也就是符合 <tt class="LITERAL">WHERE</tt> 子句中每个条件的部分。用于这个目的的信息存储在 <a href="catalog-pg-statistic.html"><tt class="STRUCTNAME">pg_statistic</tt></a> 系统表中。在 <tt class="STRUCTNAME">pg_statistic</tt> 中的记录是由 <tt class="COMMAND">ANALYZE</tt> 和 <tt class="COMMAND">VACUUM ANALYZE</tt> 命令更新的，并且总是近似值，即使刚刚更新完也不例外。</p>
<a name="AEN16896"></a>
<p>除了直接查看 <tt class="STRUCTNAME">pg_statistic</tt> 之外，我们手工检查统计的时候最好查看它更具可读性的 <tt class="STRUCTNAME">pg_stats</tt> 视图。而且，<tt class="STRUCTNAME">pg_stats</tt> 是所有人都可以读取的，而 <tt class="STRUCTNAME">pg_statistic</tt> 只能由超级用户读取。这样就可以避免非特权用户从统计信息中获取一些和其他人的表内容相关的信息。<tt class="STRUCTNAME">pg_stats</tt> 视图是受约束的，只显示当前用户可读的表。比如，我们可以：</p>
<pre class="SCREEN">SELECT attname, n_distinct, most_common_vals FROM pg_stats WHERE tablename = 'road';

 attname | n_distinct |                                                                                                                                                                                  most_common_vals
---------+------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 name    |  -0.467008 | {"I- 580                        Ramp","I- 880                        Ramp","Sp Railroad                       ","I- 580                            ","I- 680                        Ramp","I- 80                         Ramp","14th                          St  ","5th                           St  ","Mission                       Blvd","I- 880                            "}
 thepath |         20 | {"[(-122.089,37.71),(-122.0886,37.711)]"}
(2 rows)</pre>
<p><tt class="STRUCTNAME">pg_stats</tt> 在<a href="view-pg-stats.html">节43.46</a>里详细描述。</p>
<p>在 <tt class="STRUCTNAME">pg_statistic</tt> 中存储的信息的数量，特别是给每个字段用的 <tt class="STRUCTFIELD">most_common_vals</tt> 和 <tt class="STRUCTFIELD">histogram_bounds</tt> 数组上的最大记录数目可以用 <tt class="COMMAND">ALTER TABLE SET STATISTICS</tt> 命令设置，或者是用运行时参数 <a href="runtime-config-query.html#GUC-DEFAULT-STATISTICS-TARGET">default_statistics_target</a> 进行全局设置。目前缺省的限制是 10 个记录。提升该限制应该可以做出更准确的规划器估计，特别是对那些有不规则数据分布的字段而言，代价是在 <tt class="STRUCTNAME">pg_statistic</tt> 里使用了更多空间，并且需要略微多一些的时间计算估计数值。相比之下，比较低的限制可能更适合那些数据分布比较简单的字段。</p>
</div>
<div>
<hr align="LEFT" width="100%">
<table summary="Footer navigation table" width="100%" border="0" cellpadding="0" cellspacing="0">
<tr><td width="33%" align="left" valign="top"><a href="using-explain.html" accesskey="P">后退</a></td><td width="34%" align="center" valign="top"><a href="index.html" accesskey="H">首页</a></td><td width="33%" align="right" valign="top"><a href="explicit-joins.html" accesskey="N">前进</a></td></tr>
<tr><td width="33%" align="left" valign="top">使用 <tt class="COMMAND">EXPLAIN</tt></td><td width="34%" align="center" valign="top"><a href="performance-tips.html" accesskey="U">上一级</a></td><td width="33%" align="right" valign="top">用明确的 <tt class="LITERAL">JOIN</tt> 控制规划器</td></tr>
</table>
</div>
</body></html>